package com.heima.comment.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.api.UserFeginClient;
import com.heima.comment.dtos.ApCommentVo;
import com.heima.comment.dtos.CommentLikeDto;
import com.heima.comment.dtos.CommentListDto;
import com.heima.comment.dtos.CommentSaveDto;
import com.heima.comment.pojos.ApComment;
import com.heima.comment.pojos.ApCommentLike;
import com.heima.comment.service.CommentService;
import com.heima.common.constans.HotArticleConstants;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.mess.UpdateArticleMess;
import com.heima.model.user.pojos.ApUser;
import com.heima.utils.thread.AppThreadLocalUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class CommentServiceImpl implements CommentService {
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private UserFeginClient userFeginClient;

    @Autowired
    private KafkaTemplate<String,String> kafkaTemplate;



    /**
     * 发表评论
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult saveComment(CommentSaveDto dto) {
        //1.参数校验
        if (dto.getArticleId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        if(StringUtils.isBlank(dto.getContent())){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"评论内容不可以为空");
        }
        if (dto.getContent() != null && dto.getContent().length() > 140) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE, "评论内容不能超过140字");
        }

        //2.获取用户id
        ApUser apUser = AppThreadLocalUtil.getApUser();
        //如果没有登录，则不能执行以下步骤，游客身份
        if(apUser!=null && apUser.getId()==0){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }

        //3.先查询redis,获取用户信息，如果不存在，则远程调用user服务，并添加数据到redis
        String key="LOGIN_USER_"+apUser.getId();
        String apUserStr = redisTemplate.opsForValue().get(key);
        if(apUserStr==null){//redis中不存在
            ResponseResult<ApUser> result = userFeginClient.findApUserById(apUser.getId());
            if(result.getCode()==200){
                apUser = result.getData();
                //添加数据到redis中一份
                redisTemplate.opsForValue().set(key, JSON.toJSONString(apUser),2, TimeUnit.HOURS);
            }
        }else{//redis中存在
            apUser=JSON.parseObject(apUserStr,ApUser.class);
        }
        //3.5 对文本内容进行安全过滤，调用内容安全审核接口

        //4.保存数据到mongo中
        ApComment apComment=new ApComment();
        apComment.setLikes(0);
        apComment.setContent(dto.getContent());
        apComment.setTargetId(String.valueOf(dto.getArticleId()));
        apComment.setReply(0);
        apComment.setImage(apUser.getImage());
        apComment.setCreatedTime(new Date());
        apComment.setUpdatedTime(new Date());
        apComment.setNickName(apUser.getName());
        apComment.setUserId(apUser.getId());
        mongoTemplate.save(apComment);


        UpdateArticleMess mess=new UpdateArticleMess();
        mess.setArticleId(dto.getArticleId());
        mess.setType(UpdateArticleMess.UpdateArticleType.COMMENT);
        mess.setAdd(1);
        //发送消息给kafka
        kafkaTemplate.send(HotArticleConstants.HOT_ARTICLE_SCORE_TOPIC, JSON.toJSONString(mess));

        return ResponseResult.okResult("发表评论成功");
    }

    /**
     * 点赞评论
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult likeComment(CommentLikeDto dto) {
        //1.参数校验
        if(dto==null || dto.getCommentId()==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //2.获取用户id
        ApUser apUser = AppThreadLocalUtil.getApUser();
        //如果没有登录，则不能执行以下步骤，游客身份
        if(apUser!=null && apUser.getId()==0){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }

        //2.5去查询mongo中评论集合
        ApComment apComment = mongoTemplate.findById(dto.getCommentId(), ApComment.class);
        if(apComment==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }


        //3.查询redis,是否点赞过
        String key="COMMENT_LIKE_"+apUser.getId();
        //判断当前redis中是否是当前成员内容，true表示是
        Boolean memberFlag = redisTemplate.opsForSet().isMember(key, dto.getCommentId());

        //4.如果点赞过，并且正在执行的是点赞操作operation=0,则返回信息
        if(memberFlag && dto.getOperation()==0){
            return ResponseResult.errorResult(AppHttpCodeEnum.LIKE_COMMENT_END);
        }

        //5.如果点赞过，正在执行的是取消点赞，operation=1，则删除redis,删除mongo点赞集合,修改评论集合中的点赞数-1
        if(memberFlag && dto.getOperation()==1){
            //删除redis
            redisTemplate.opsForSet().remove(key,dto.getCommentId());
            //删除mong点赞集合
            mongoTemplate.remove(Query.query(
                    Criteria.where("userId").is(apUser.getId()).and("targetId").is(dto.getCommentId())
            ), ApCommentLike.class);
            //修改评论集合-1
            /*apComment.setLikes(apComment.getLikes()>0?apComment.getLikes()-1:0);
            mongoTemplate.save(apComment);*/
            Query query=Query.query(
                    Criteria.where("id").is(dto.getCommentId()).and("likes").gt(0)
            );
            UpdateDefinition update=new Update().inc("likes",-1);
            mongoTemplate.updateFirst(query,update,ApComment.class);
        }

        //6.如果没有点赞过，正在执行的是点赞，operation=0，则新增redis,新增mongo点赞集合,修改评论集合中的点赞数+1
        if(!memberFlag && dto.getOperation()==0){
            //新增redis
            redisTemplate.opsForSet().add(key,dto.getCommentId());
            //新增点赞集合
            ApCommentLike apCommentLike=new ApCommentLike();
            apCommentLike.setCreatedTime(new Date());
            apCommentLike.setTargetId(dto.getCommentId());
            apCommentLike.setUserId(apUser.getId());
            mongoTemplate.insert(apCommentLike);
            //修改评论集合+1
          /*  apComment.setLikes(apComment.getLikes()+1);
            mongoTemplate.save(apComment);*/
            Query query=Query.query(
                    Criteria.where("id").is(dto.getCommentId())
            );
            UpdateDefinition update=new Update().inc("likes",1);
            mongoTemplate.updateFirst(query,update,ApComment.class);
        }

        apComment = mongoTemplate.findById(dto.getCommentId(), ApComment.class);

        Map map=new HashMap();
        map.put("likes",apComment.getLikes());
        return ResponseResult.okResult(map);
    }

    /**
     * 查询评论列表
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult listComment(CommentListDto dto) {
        //1.参数检查
        if(dto.getArticleId()==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        if(dto.getSize()==null || dto.getSize()==0){
            dto.setSize(10);
        }

        //2.根据文章id去查询mongo,倒叙展示和分页查询
        List<ApComment> apCommentsList = mongoTemplate.find(Query.query(
                Criteria.where("targetId").is(dto.getArticleId().toString()).and("createdTime").lte(dto.getMinDate())
        ).with(Sort.by(Sort.Direction.DESC,"updatedTime"))//排序
                .limit(dto.getSize())//分页
                , ApComment.class);


        ApUser apUser = AppThreadLocalUtil.getApUser();
        //3.如果是游客身份
        if(apUser!=null && apUser.getId()==0){
            //直接返回list集合
            return ResponseResult.okResult(apCommentsList);
        }else{
            //4.如果是登录用户，我们要让点赞按钮高亮（如果该用户点赞过）
            String key="COMMENT_LIKE_"+apUser.getId();
            //根据key获取所有的redis的value,包含都是点赞过的评论id,001,002,003
            Set<String> memberIdSet = redisTemplate.opsForSet().members(key);
            //遍历apCommentsList，然后比较当前list中的id是否存在于memberId中，如果存在，则认为点赞过，否则没有点赞过
            List<ApCommentVo> commentVoList = apCommentsList.stream().map(apComment -> {

                ApCommentVo vo = new ApCommentVo();
                BeanUtils.copyProperties(apComment, vo);
                //1.获取每个list中的评论的id
                String commentId = apComment.getId();
                //2.看当前id是否存在于set集合中
                if (memberIdSet.contains(commentId)) {
                    //我们就认为点赞过
                    vo.setOperation((short) 0);
                }
                return vo;
            }).collect(Collectors.toList());
            return ResponseResult.okResult(commentVoList);
        }
    }
}
